package session

import (
	"common-api/logs"
	"common-api/message"
	"common-api/process"
	"common-api/serialization"
	"context"
	"encoding/binary"
	"io"
	"net"
	"sync/atomic"
)

type Session struct {
	Conn  net.Conn
	state atomic.Bool
}

func NewSession(conn net.Conn) *Session {
	s := &Session{
		Conn: conn,
	}
	s.state.Store(true) // 默认将状态设置为true
	return s
}

func (s *Session) Close() {
	if s.state.CompareAndSwap(true, false) {
		s.Conn.Close()
	}
}

func (s *Session) ReceiveMessage() error {
	logs.Logger.Debugln("start receive message...")
	//读取整个消息的长度
	length := make([]byte, 4)
	if _, err := io.ReadFull(s.Conn, length); err != nil {
		logs.Logger.Errorf("read message length error: %v", err)
		return err
	}
	//读取消息体
	messageLength := binary.BigEndian.Uint32(length)
	logs.Logger.Debugln("message length:%v", messageLength)
	dataBytes := make([]byte, messageLength)
	if _, err := io.ReadFull(s.Conn, dataBytes); err != nil {
		logs.Logger.Errorf("read body error:", err)
		return err
	}
	headerLength := binary.BigEndian.Uint32(dataBytes[:4])
	headerDataBytes := dataBytes[4 : headerLength+4]
	commonMessage := &message.HeaderMessage{}
	serialization.JsonDecode(headerDataBytes, commonMessage)

	bodyLength := messageLength - (uint32(len(headerDataBytes))) - 4
	if bodyLength > 0 {
		bodyDataBytes := dataBytes[messageLength-bodyLength:]
		commonMessage.Body = bodyDataBytes
	}
	ctx := context.Background()
	ctx = context.WithValue(ctx, "session", s)
	if commonMessage.Type == message.RequestType {
		process.ProcessRequestCommand(commonMessage, ctx)
	} else if commonMessage.Type == message.ResponseType {
		logs.Logger.Debugln("Receive message response Type code: %v", commonMessage.Code)
		logs.Logger.Debugln("Receive message response Data: %s", string(commonMessage.Body))
		process.ProcessResponseCommand(commonMessage)
	}
	return nil

}

func (s *Session) WriteMessage(data *message.HeaderMessage) error {
	err, headerBytes := data.Encode()
	if err != nil {
		logs.Logger.Errorf("encode header message error: %v", err)
		return err
	}
	bodyBytesLength := uint32(len(data.Body))
	headerBytesLength := uint32(len(headerBytes))
	messageLengthBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(messageLengthBytes, bodyBytesLength+headerBytesLength+4)
	if _, err := s.Conn.Write(messageLengthBytes); err != nil {
		logs.Logger.Errorf("wirte header message length: %v", err)
		return err
	}
	headerLengthBytes := make([]byte, 4)
	binary.BigEndian.PutUint32(headerLengthBytes, headerBytesLength)
	if _, err := s.Conn.Write(headerLengthBytes); err != nil {
		logs.Logger.Errorf("wirte message length: %v", err)
		return err
	}
	if _, err := s.Conn.Write(headerBytes); err != nil {
		logs.Logger.Errorf("wirte header bytes date: %v", err)
		return err
	}
	if _, err := s.Conn.Write(data.Body); err != nil {
		logs.Logger.Errorf("wirte body message bytes date: %v", err)
		return err
	}
	return nil
}
